From 9180fdea2d446513bdae681431cb4d872f9214cb Mon Sep 17 00:00:00 2001
From: Andrew Eikum <aeikum@codeweavers.com>
Date: Tue, 7 Apr 2020 11:05:47 -0500
Subject: [PATCH] winepulse: Add stub IAudioClockAdjustment implementation

---
 dlls/winepulse.drv/mmdevdrv.c | 47 +++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 6a2906761a7..c5f12301c2e 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -162,6 +162,7 @@ struct ACImpl {
     IAudioCaptureClient IAudioCaptureClient_iface;
     IAudioClock IAudioClock_iface;
     IAudioClock2 IAudioClock2_iface;
+    IAudioClockAdjustment IAudioClockAdjustment_iface;
     IAudioStreamVolume IAudioStreamVolume_iface;
     IUnknown *marshal;
     IMMDevice *parent;
@@ -206,6 +207,7 @@ static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
 static const IAudioClockVtbl AudioClock_Vtbl;
 static const IAudioClock2Vtbl AudioClock2_Vtbl;
+static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl;
 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
 
 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
@@ -250,6 +252,11 @@ static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
     return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
 }
 
+static inline ACImpl *impl_from_IAudioClockAdjustment(IAudioClockAdjustment *iface)
+{
+    return CONTAINING_RECORD(iface, ACImpl, IAudioClockAdjustment_iface);
+}
+
 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
 {
     return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
@@ -1246,6 +1253,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
+    This->IAudioClockAdjustment_iface.lpVtbl = &AudioClockAdjustment_Vtbl;
     This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
     This->dataflow = dataflow;
     This->parent = dev;
@@ -1278,6 +1286,8 @@ static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
     *ppv = NULL;
     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
         *ppv = iface;
+    else if (IsEqualIID(riid, &IID_IAudioClockAdjustment))
+        *ppv = &This->IAudioClockAdjustment_iface;
     if (*ppv) {
         IUnknown_AddRef((IUnknown*)*ppv);
         return S_OK;
@@ -2728,6 +2738,43 @@ static const IAudioClock2Vtbl AudioClock2_Vtbl =
     AudioClock2_GetDevicePosition
 };
 
+static HRESULT WINAPI AudioClockAdjustment_QueryInterface(IAudioClockAdjustment *iface,
+        REFIID riid, void **ppv)
+{
+    ACImpl *This = impl_from_IAudioClockAdjustment(iface);
+    return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
+}
+
+static ULONG WINAPI AudioClockAdjustment_AddRef(IAudioClockAdjustment *iface)
+{
+    ACImpl *This = impl_from_IAudioClockAdjustment(iface);
+    return IAudioClient_AddRef(&This->IAudioClient_iface);
+}
+
+static ULONG WINAPI AudioClockAdjustment_Release(IAudioClockAdjustment *iface)
+{
+    ACImpl *This = impl_from_IAudioClockAdjustment(iface);
+    return IAudioClient_Release(&This->IAudioClient_iface);
+}
+
+static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment *iface,
+        float new_rate)
+{
+    ACImpl *This = impl_from_IAudioClockAdjustment(iface);
+
+    TRACE("(%p)->(%f)\n", This, new_rate);
+
+    return E_NOTIMPL;
+}
+
+static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl =
+{
+    AudioClockAdjustment_QueryInterface,
+    AudioClockAdjustment_AddRef,
+    AudioClockAdjustment_Release,
+    AudioClockAdjustment_SetSampleRate
+};
+
 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
         IAudioStreamVolume *iface, REFIID riid, void **ppv)
 {
From 21888ad1af89c449b78d3fc5aaa71e9608d50e42 Mon Sep 17 00:00:00 2001
From: Andrew Eikum <aeikum@codeweavers.com>
Date: Tue, 7 Apr 2020 14:01:02 -0500
Subject: [PATCH] winepulse: Implement IAudioClockAdjustment::SetSampleRate

---
 dlls/winepulse.drv/mmdevdrv.c | 73 +++++++++++++++++++++++++++++++++--
 1 file changed, 70 insertions(+), 3 deletions(-)

diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index c5f12301c2e..eeb153f78b1 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -493,7 +493,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
         ret = -1;
     else if (render)
         ret = pa_stream_connect_playback(stream, NULL, &attr,
-        PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
+        PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS|PA_STREAM_VARIABLE_RATE, NULL, NULL);
     else
         ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS);
     if (ret >= 0) {
@@ -1163,7 +1163,7 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
     dump_attr(&attr);
     if (This->dataflow == eRender)
         ret = pa_stream_connect_playback(This->stream, NULL, &attr,
-        PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY|moving, NULL, NULL);
+        PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY|PA_STREAM_VARIABLE_RATE|moving, NULL, NULL);
     else
         ret = pa_stream_connect_record(This->stream, NULL, &attr,
         PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY|moving);
@@ -2757,14 +2757,81 @@ static ULONG WINAPI AudioClockAdjustment_Release(IAudioClockAdjustment *iface)
     return IAudioClient_Release(&This->IAudioClient_iface);
 }
 
+static BOOL pulse_update_sample_rate(ACImpl *This, uint32_t new_rate)
+{
+    pa_operation *o;
+    int success;
+
+    o = pa_stream_update_sample_rate(This->stream, new_rate, pulse_op_cb, &success);
+    if (o)
+    {
+        while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
+            pthread_cond_wait(&pulse_cond, &pulse_lock);
+        pa_operation_unref(o);
+    } else
+        success = 0;
+
+    return success != 0;
+}
+
 static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment *iface,
         float new_rate)
 {
     ACImpl *This = impl_from_IAudioClockAdjustment(iface);
+    int success;
+    uint32_t old_rate;
+    pa_operation *o;
+    HRESULT hr;
+    pa_buffer_attr attr;
 
     TRACE("(%p)->(%f)\n", This, new_rate);
 
-    return E_NOTIMPL;
+    pthread_mutex_lock(&pulse_lock);
+    hr = pulse_stream_valid(This);
+    if (FAILED(hr)) {
+        pthread_mutex_unlock(&pulse_lock);
+        return hr;
+    }
+
+    if(!pulse_update_sample_rate(This, new_rate)){
+        WARN("Something went wrong during update_sample_rate\n");
+        pthread_mutex_unlock(&pulse_lock);
+        return E_FAIL;
+    }
+
+    old_rate = This->ss.rate;
+    This->ss.rate = new_rate;
+    This->period_bytes = pa_frame_size(&This->ss) * MulDiv(This->mmdev_period_usec, This->ss.rate, 1000000);
+
+    attr.minreq = attr.fragsize = This->period_bytes;
+    attr.tlength = This->period_bytes * 3;
+    attr.maxlength = This->bufsize_frames * pa_frame_size(&This->ss);
+    attr.prebuf = pa_frame_size(&This->ss);
+
+    o = pa_stream_set_buffer_attr(This->stream, &attr, pulse_op_cb, &success);
+    if (o)
+    {
+        while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
+            pthread_cond_wait(&pulse_cond, &pulse_lock);
+        pa_operation_unref(o);
+    } else
+        success = 0;
+
+    if(!success){
+        WARN("Something went wrong during set_buffer_attr\n");
+        if(pulse_update_sample_rate(This, old_rate)){
+            This->ss.rate = old_rate;
+            This->period_bytes = pa_frame_size(&This->ss) * MulDiv(This->mmdev_period_usec, This->ss.rate, 1000000);
+        }
+        pthread_mutex_unlock(&pulse_lock);
+        return E_FAIL;
+    }
+
+    TRACE("period_bytes now: %u\n", This->period_bytes);
+
+    pthread_mutex_unlock(&pulse_lock);
+
+    return S_OK;
 }
 
 static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl =
 
